package org.lecric.wind44.client;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.lecric.wind44.client.model.Spot;
import org.lecric.wind44.client.model.SpotInformation;
import org.lecric.wind44.client.model.Spots;
import org.lecric.wind44.client.widget.BoardShapeComparator;
import org.lecric.wind44.client.widget.CachedFrame;
import org.lecric.wind44.client.widget.Calculator;
import org.lecric.wind44.client.widget.Map44;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.ComplexPanel;
import com.google.gwt.user.client.ui.DeckPanel;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.Frame;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.TabBar;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.VerticalSplitPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Wind44 implements EntryPoint
{
	private static final String TOOLS_TAB_NAME = "Tools";
	private static final String MAP_TAB_NAME = "Map";
	private static final String CALC_TAB_NAME = "Sails Calculator";
	private static final String BOARD_SHAPE_TAB_NAME = "Board Shape Comparator";
	private static final String HELP_TAB_NAME = "?";
	private static final String SPLIT_TAB_NAME = ">>";
	protected static final int HEIGHT_MARGIN = 10;
	private Widget mainPanel;
	private Timer loadingTimer;

	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad() {
		loadingTimer = new Timer() {
			private int i=0;
			@Override
			public void run() {
				i++;
				String text="Loading";
				for(int j=0; j <= i%3 ; j++)
				{
					text+='.';
				}
				Document.get().getElementById("loading").setInnerText(text);
			}
		};
		loadingTimer.run();
		loadingTimer.scheduleRepeating(1000);
		createPanel(RootPanel.get("main"));
		Window.addResizeHandler(new ResizeHandler() {
			@Override
			public void onResize(ResizeEvent event) {
				updateHeight();
			}
		}) ;
	}
	
	private void adjustHeight(int height, Widget w)
	{
		if(w instanceof ComplexPanel)
		{
			ComplexPanel complexPanel=(ComplexPanel) w;
			ArrayList<Widget> widgets=new ArrayList<Widget>();
			for(int i=0; i < complexPanel.getWidgetCount() ; i++)
			{
				Widget child=complexPanel.getWidget(i);
				widgets.add(child);
			}
			adjustHeight(height, widgets);
		}
		else if(w instanceof VerticalSplitPanel)
		{
			VerticalSplitPanel splitPanel=(VerticalSplitPanel) w;
			splitPanel.setHeight(height + "px");
			ArrayList<Widget> widgets=new ArrayList<Widget>();
//			GWT.log("top widget:"+splitPanel.getTopWidget().getOffsetHeight()
//					+";height="+splitPanel.getTopWidget().getElement().getScrollHeight(), null);
			widgets.add(splitPanel.getTopWidget());
			widgets.add(splitPanel.getBottomWidget());
			adjustHeight(height, widgets);
		}
	}

	private void adjustHeight(int height, List<Widget> widgets)
	{
		for(Widget w: widgets)
		{
			//GWT.log(w.getClass() + ":" + w.getOffsetHeight(), null);
			if(w instanceof Frame)
			{
				w.setHeight(height + "px");
			}
			if(w instanceof DeckPanel)
			{
				for(Widget w2: widgets)
				{
					if(!w.equals(w2))
						height-=w2.getOffsetHeight();
				}
				w.setHeight(height + "px");
				adjustHeight(height, w);
			}
			else
			{
				adjustHeight(w.getElement().getScrollHeight(), w);
			}
		}
	}

	private void createPanel(final Panel rootPanel) {
		SpotUtils.getSpots(new AsyncCallback<Spots>(){
			@Override
			public void onFailure(Throwable e) {
				GWT.log("Failed retrieving spots", e);
				rootPanel.add(new Calculator().getWidget());
				PopupPanel popupPanel=new PopupPanel(true, false);
				popupPanel.setWidget(new HTML("<font size='30'>Full version available on <a href='http://wind-44.appspot.com/#Calculator'>Wind44</a>.</font>"));
				popupPanel.setTitle("Information");
				popupPanel.center();
				popupPanel.show();
				end();
			}
			@Override
			public void onSuccess(Spots spots) {
				ArrayList<Spot> publicSpots=new ArrayList<Spot>();
				for(Spot spot: spots.getSpots())
				{
					if(spot.isPub())
						publicSpots.add(spot);
				}
				setMainPanel(createPanel(rootPanel, publicSpots, true));
				end();
			}
			private void end() {
				loadingTimer.cancel();
				Document.get().getElementById("loading").setInnerText("");
			}
		});
	}
	
	private ComplexPanel createPanel(final Panel rootPanel, final List<Spot> spots, boolean showPopup) {
		final VerticalPanel panel=new VerticalPanel();
		final CachedFrame frame=new CachedFrame();
		frame.setWidth("100%");
		final TabBar mainBar=new TabBar();
		final TabBar bar=new TabBar();
		final HashMap<Integer, String> tokens=new HashMap<Integer, String>();
		int tokenCount=0;

		for(Spot spot: SpotUtils.sort(spots))
		{
			mainBar.addTab(spot.getName());
			tokens.put(tokenCount++, spot.getName());
		}

		mainBar.addTab(createLabel(SPLIT_TAB_NAME, "Split Vertically (experimental)"));
		tokenCount++;

		mainBar.addTab(TOOLS_TAB_NAME);
		tokens.put(tokenCount++, TOOLS_TAB_NAME);
//		final TabBar toolsBar=new TabBar();
//		toolsBar.addTab(MAP_TAB_NAME);
//		toolsBar.addTab(CALC_TAB_NAME);
//		toolsBar.addTab(BOARD_SHAPE_TAB_NAME);
//		toolsBar.addSelectionHandler(new SelectionHandler<Integer>(){
//			@Override
//			public void onSelection(SelectionEvent<Integer> event) {
//				Integer index = event.getSelectedItem();
//				String tabName=mainBar.getTabHTML(index);
//				
//			}
//		});

		Image editImage = createImage("images/edit.gif", "Suggest a new Spot or Web site");
		editImage.setSize("19px", "19px");
		mainBar.addTab(editImage);
		mainBar.addSelectionHandler(new SelectionHandler<Integer>(){
			@Override
			public void onSelection(SelectionEvent<Integer> event) {
				while(bar.getTabCount()>0)
				{
					bar.removeTab(0);
				}
				Integer index = event.getSelectedItem();
				if(tokens.containsKey(index))
					History.newItem(tokens.get(index));
				if(index < spots.size())
				{
					Spot spot=SpotUtils.sort(spots).get(index);
					for(SpotInformation info: SpotUtils.sort(spot.getInfos()))
					{
						if(info.isPub())
							bar.addTab(info.getName());
					}
				}
				else
				{
					String tabName=mainBar.getTabHTML(index);
					if(SPLIT_TAB_NAME.equals(tabName))
					{
						// More
						rootPanel.remove(panel);
						VerticalSplitPanel splitPanel=new VerticalSplitPanel();
						splitPanel.setTopWidget(panel);
						SimplePanel spanel=new SimplePanel();
						spanel.setWidth("100%");
						createPanel(spanel, spots, false);
						splitPanel.setBottomWidget(spanel);
						rootPanel.add(splitPanel);
						setMainPanel(splitPanel);
					}
					else if(HELP_TAB_NAME.equals(tabName))
					{
						frame.setUrl("help.html");
					}
					else if(TOOLS_TAB_NAME.equals(tabName))
					{
						bar.addTab(MAP_TAB_NAME);
						bar.addTab(CALC_TAB_NAME);
						bar.addTab(BOARD_SHAPE_TAB_NAME);
					}
					else if(tabName.contains("edit.gif"))
					{
						frame.setUrl("login?site=/Suggest.html");
					}
				}
			}
		});
		bar.addSelectionHandler(new SelectionHandler<Integer>(){
			@Override
			public void onSelection(SelectionEvent<Integer> event) {
				String tabName=mainBar.getTabHTML(mainBar.getSelectedTab());
				if(TOOLS_TAB_NAME.equals(tabName))
				{
					tabName=bar.getTabHTML(event.getSelectedItem());
					if(MAP_TAB_NAME.equals(tabName))
					{
						Map44 map44=new Map44(spots);
						frame.setWidget(map44.getMapWidget());
						map44.getMapWidget().checkResize();
					}
					else if(CALC_TAB_NAME.equals(tabName))
					{
						frame.setWidget(new Calculator().getWidget());
					}
					else if(BOARD_SHAPE_TAB_NAME.equals(tabName))
					{
						frame.setWidget(new BoardShapeComparator().getWidget());
					}
				}
				else
				{
					Spot spot=SpotUtils.sort(spots).get(mainBar.getSelectedTab());
					SpotInformation info=SpotUtils.sort(spot.getInfos()).get(event.getSelectedItem());
					frame.setUrl(info.getUrl());
				}
//				GWT.log(frame.getElement().getScrollHeight() + "", null);
//				frame.setHeight(frame.getElement().getScrollHeight() + "px");
			}
		});
		panel.setWidth("100%");
		VerticalPanel vpanel=new VerticalPanel();
		HorizontalPanel hpanel=new HorizontalPanel();
		hpanel.setSpacing(10);
		hpanel.add(mainBar);
		Image reloadImage=createImage("images/reload.gif", "Reload page");
		reloadImage.addClickHandler(new ClickHandler(){
			@Override
			public void onClick(ClickEvent event) {
				frame.reload();
			}
		});
		hpanel.add(reloadImage);
		vpanel.add(hpanel);
		vpanel.add(bar);
		final DisclosurePanel disclosurePanel=new DisclosurePanel("Click to Show/Hide", true);
		disclosurePanel.setContent(vpanel);
		panel.add(GWT.isScript() ? vpanel : disclosurePanel);
		panel.add(frame);
		rootPanel.add(panel);
		if(showPopup)
		{
			Anchor anchor=new Anchor("login", "login?site=/Wind44.html&force=true");
			hpanel.add(anchor);
		}
		// Auto select the correct index:
		String token = History.getToken();
		if(token!=null)
		{
			for(int i: tokens.keySet())
			{
				String value=tokens.get(i);
				if(token.equals(value))
					mainBar.selectTab(i);
			}
		}
		
		return panel;
	}

	private Image createImage(String url, String title/*, ClickHandler handler*/) {
		Image image = new Image(url);
		image.setTitle(title);
		return image;
	}

	private Label createLabel(String name, String title) {
		Label suggestLabel=new Label(name);
		suggestLabel.setTitle(title);
		return suggestLabel;
	}

	private void updateHeight()
	{
		adjustHeight(Window.getClientHeight() - HEIGHT_MARGIN, mainPanel);
	}

	private void setMainPanel(Widget panel)
	{
		mainPanel=panel;
		updateHeight();
	}
}
